#include "comthread_f210.h"
#include <QSerialPortInfo>
#include <QDebug>
#include <QApplication>
#include "my_crc.h"

/* mSerial : 串口
 * RecvTimer : 接收定时器，串口接收数据后触发数据接收
 * RecvTime  : 延时N ms后接收数据
 * RespTimer : 等待响应定时器，200ms/次的判断(第一次1s)，共计6次
 * RespStu   : 等待响应状态，判断设备是否无响应
 */
comthread_f210::comthread_f210(QObject *parent) : QThread(parent)
{
    mSerial    = new QSerialPort;
    mSerial->moveToThread(this);
    RecvTimer  = new QTimer;
    RecvTime   = 200;
    RespTimer  = new QTimer;
    RespStu    = WAIT_STU_WAIT;
    WaitTimer  = new QTimer;
    RecvTimeOut = 0;
    // 读取数据
    connect(mSerial,&QSerialPort::readyRead,this,&comthread_f210::SerialPort_Read_Start);
    connect(RecvTimer,&QTimer::timeout,this,&comthread_f210::ReceviceSerialData);
    connect(RespTimer,&QTimer::timeout,this,&comthread_f210::RespTimer_TimeOut);
//    connect(WaitTimer,&QTimer::timeout,this,&comthread_f210::WaitTimer_TimeOut);
}

QStringList comthread_f210::GetSerialAvailable()
{
    QStringList mPortsList;

    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        mPortsList << info.portName();
    }
    return mPortsList;
}

bool comthread_f210::InitSerial(QString portname)
{
    // 设置端口部分参数
    mSerial->setBaudRate(QSerialPort::Baud115200);
    mSerial->setDataBits(QSerialPort::Data8);
    mSerial->setParity(QSerialPort::NoParity);
    mSerial->setStopBits(QSerialPort::OneStop);
    mSerial->setPortName(portname);
    if(!mSerial->open(QIODevice::ReadWrite))
    {
        qDebug()<<"Serial port opening failed";
        return false;
    }
    // 115200 N-8-1
    qDebug()<<"Serial port open successfully";

    return true;
}

void comthread_f210::CloseSerial()
{
    if(WaitTimer->isActive())
    {
        WaitTimer->stop();
    }
    if(RespTimer->isActive())
    {
        RespTimer->stop();
    }
    if(RecvTimer->isActive())
    {
        RecvTimer->stop();
    }
    if(mSerial->isOpen())
    {
        mSerial->clear();
        mSerial->close();
    }
    qDebug()<<"Serial port closed successfully";
}

//数据接收:触发中断->延时后接收数据
void comthread_f210::SerialPort_Read_Start()
{
    if(!RecvTimer->isActive())
    {
        RecvTimer->start(RecvTime);
    }
}
// 接收数据
void comthread_f210::ReceviceSerialData()
{
    RecvTimer->stop();
    QByteArray buffer = mSerial->readAll();
    if(F210_Cmd_Check(buffer))
    {
        uint32_t CmdId = ((buffer[7] << 24)&0xFF000000) | ((buffer[6] << 16)&0x00FF0000) | ((buffer[5] << 8)&0x0000FF00) | ((buffer[4] << 0)&0x000000FF);
        if(CmdId == 0x000a0000)
        {
            RespStu = WAIT_STU_REPT;
        }
        else
        {
            RespStu = WAIT_STU_DATA;
            emit UpdateSerialData(buffer);
        }
    }
    qDebug() << buffer.size();
}

// 超时处理
void comthread_f210::RespTimer_TimeOut()
{
    RespStu = WAIT_STU_OUT;
}
bool comthread_f210::RecvData_TimeOut(QByteArray data)
{
    int OutCnt = 0;
    int TimeStart = 1000;
    int TimeOut = 1000;
    int TimeCnt = 0;
    if(RecvTimeOut > TimeOut)
    {
        TimeOut = RecvTimeOut;
    }
    LastCmd = data;
    do
    {
        mSerial->write(data);
        if(!RecvTimer->isActive())
        {
            RespStu = WAIT_STU_WAIT;
        }
        RespTimer->start(TimeStart);
        while(WAIT_STU_WAIT == RespStu)QCoreApplication::processEvents();
        RespTimer->stop();
        TimeCnt += TimeStart;
        if(WAIT_STU_REPT == RespStu)
        {
            OutCnt = 0;
            TimeStart = 1000;
            TimeOut = RecvTimeOut;
            TimeCnt = 0;
        }
        else if((WAIT_STU_OUT == RespStu) && (TimeOut == TimeCnt))
        {
            OutCnt++;
            TimeStart = 500;
            TimeOut = 500;
            TimeCnt = 0;
        }
        else
        {
            return true;
        }
    }while(5 > OutCnt);

    data.clear();
    data.append("timeout");
    emit UpdateSerialData(data);

    return false;
}

/* 同步定时器
 * 每隔5秒发送一次同步指令
 */
void comthread_f210::WaitTimer_TimeStart()
{
    WaitTimer->start(5000);
}
void comthread_f210::WaitTimer_TimeStop()
{
    WaitTimer->stop();
}
bool comthread_f210::WaitTimer_TimeActive()
{
    return WaitTimer->isActive();
}
void comthread_f210::WaitTimer_TimeOut()
{
    // 或许应该加一个限制条件，确保同步指令在其它命令结束后发出
    SendSerial_LinkCmd_Wait();
}

/* 延时时间初始化
 * 根据数据长度 初始化 接收数据前的延时时间
 */
void comthread_f210::RecvTime_Init(long DataSize)
{
    long SendTime = DataSize*90;// 115200波特率的每个字节发送时间约为90us

    RecvTime = SendTime/1000;   // 余数省去，因为后续间隔只多不少
    RecvTime = 20 + RecvTime*2; // 20:发送接收间隔,随数据量增大而增大

    RecvTimeOut = RecvTime;
}

void comthread_f210::SendSerialData(QByteArray data)
{
    RecvTime_Init(data.size());
    // 接收GUI数据并发送
    mSerial->write(data);
}

// 连接指令集
void comthread_f210::SendSerial_LinkCmd_Link()   //连接
{
    QByteArray data;
    data.clear();
    data.append(PORT_SIZE_MAX_F210, char(0));
    data[3] = 0x01;
    QByteArray LineStr;
    data = F210_CmdPacket(LineStr, data);
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void comthread_f210::SendSerial_LinkCmd_Wait()   //同步
{
    QByteArray data;
    data.clear();
    data.append(PORT_SIZE_MAX_F210, char(0));
    data[3] = 0x01;
    QByteArray LineStr;
    data = F210_CmdPacket(LineStr, data);
    RecvTime_Init(data.size());
    //
    if(!RecvData_TimeOut(data))
    {
        emit UpdateSerialData("error");
    }
}
void comthread_f210::SendSerial_LinkCmd_Break()  //断开
{
    QByteArray data;
    data.clear();
    data.append(PORT_SIZE_MAX_F210, char(0xee));
    QByteArray LineStr;
    data = F210_CmdPacket(LineStr, data);
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void comthread_f210::SendSerial_LinkCmd_Repeat()  //重发
{
    QByteArray data;
    data.clear();
    data.append(PORT_SIZE_MAX_F210, char(0));
    data[1] = 0x0a;
    QByteArray LineStr;
    data = F210_CmdPacket(LineStr, data);
    RecvTime_Init(data.size());
    //
    RecvData_TimeOut(data);
}
void comthread_f210::RecvSerial_LinkCmd_Repeat()  //接收重发
{
    RecvData_TimeOut(LastCmd);
}

//
void comthread_f210::SendSerial_MtsnCmd_SendCode(QByteArray code, uint16_t addr)
{
    //判断盖板码长度
    if(code.size() != 44)
    {
        QByteArray ErrStr;
        ErrStr.clear();
        ErrStr.append("警告:盖板码长度为");
        ErrStr.append(QString::number(code.size(), 10));
        emit UpdateSerialData(ErrStr);
        return;
    }

    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xb1;
    cmd[1] = 0x00;   // 1
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(code, cmd);
    //
    cmd.append(code);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_RecvCode(QByteArray code, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xa1;
    cmd[1] = 0x00;   // 1
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(code, cmd);
    //
    RecvTime_Init(cmd.size()+44);
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_SendData_Start(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xb1;
    cmd[1] = 0x00;
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_SendData(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xb1;
    cmd[1] = 0xA0;
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(data, cmd);
    //
    cmd.append(data);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_SendData_End(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xb3;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    RecvTimeOut = 120000;
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_RecvData_Start(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(4, char(0));
    cmd[0] = 0xa1;
    cmd[1] = 0x00;   // 1
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_RecvData(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(4, char(0));
    cmd[0] = 0xa0;
    cmd[1] = 0x00;
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
void comthread_f210::SendSerial_MtsnCmd_RecvData_End(QByteArray data, uint16_t addr)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(PORT_SIZE_MAX_F210, char(0));
    cmd[0] = 0xa3;
    cmd[1] = 0x00;   // 1
    cmd[2] = addr >> 8;
    cmd[3] = addr & 0xFF;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}

// 显示修复-读Gamma数据
void comthread_f210::SendSerial_Read_GammaData(QByteArray data, int index)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(4, char(0));
    cmd[0] = 0x15;
    cmd[3] = index;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    //
    RecvData_TimeOut(cmd);
}
// 显示修复-写Gamma数据
void comthread_f210::SendSerial_Write_GammaData(QByteArray data, int index)
{
    //指令
    QByteArray cmd;
    cmd.clear();
    cmd.append(4, char(0));
    cmd[0] = 0x1a;
    cmd[3] = index;
    cmd = F210_CmdPacket(data, cmd);
    //
    RecvTime_Init(cmd.size());
    RecvTimeOut = 1000;
    //
    RecvData_TimeOut(cmd);
}
